/**
 * 处理器上下文
 */
export interface Context {
  /**
   * 获取参数
   */
  getArgs(): any[]

  /**
   * 获取返回值
   */
  getResult(): any

  /**
   * 获取错误
   */
  getError(): any
}

/**
 * 处理方法
 */
export type Handle = (context: Context) => Promise<any>

/**
 * 前置处理方法
 */
export type PrevHandle = Handle

/**
 * 后置处理方法
 */
export type PostHandle = Handle

/**
 * 错误处理方法
 */
export type ErrorHandle = Handle

/**
 * 处理器
 */
export interface Handler {

  /**
   * 获取前置处理
   */
  getPrevHandle(context: Context): Promise<PrevHandle | undefined>

  /**
   * 获取后置处理
   */
  getPostHandle(context: Context): Promise<PostHandle | undefined>

  /**
   * 获取错误处理
   */
  getErrorHandle(context: Context): Promise<ErrorHandle | undefined>

}

/**
 * 抽象处理器
 */
export abstract class AbstractHandler implements Handler {

  /**
   * 获取前置处理
   * @param context 
   * @returns 前置处理函数
   */
  async getPrevHandle(context: Context): Promise<PrevHandle | undefined> {
    return this.prevHandle()
  }

  /**
   * 获取后置处理
   * @param context 
   * @returns 后置处理函数
   */
  async getPostHandle(context: Context): Promise<PostHandle | undefined> {
    return this.postHandle()
  }

  /**
   * 获取错误处理
   * @param context 
   * @returns 错误处理函数
   */
  async getErrorHandle(context: Context): Promise<ErrorHandle | undefined> {
    return this.errorHandle()
  }

  protected abstract prevHandle(): PrevHandle

  protected abstract postHandle(): PostHandle

  protected abstract errorHandle(): ErrorHandle

}

class DefaultContext implements Context {
  private args: any[]
  private result: any
  private error: any

  constructor(args: any[]) {
    this.args = args
  }

  getArgs() {
    return this.args
  }

  getResult() {
    return this.result
  }

  setResult(result: any) {
    this.result = result
  }

  setError(error: any) {
    this.error = error
  }

  getError() {
    return this.error
  }

}

export class Proxier {

  private static async runHandles(handlers: Handler[], context: Context, type: keyof Handler): Promise<any> {
    const handles: Handle[] = []
    for (const handler of handlers) {
      try {
        const handle = await handler[type](context)
        if (typeof handle === 'function') {
          handles.push(handle)
        }
      }
      catch(error) {
        console.log(`[${type}]:获取处理器错误`, error)
      }
    }
    
    for (const handle of handles) {
      try {
        const result = await handle(context)
        if (result !== undefined) {
          return result
        }
      }
      catch(error) {
        console.log(`[${type}]:执行处理器错误`, error)
      }
    }
  }

  private readonly handlers: Handler[] = []

  constructor(handlers: Handler[] = []) {
    this.handlers.push(...handlers)
  }

  addHandlers(...handlers: Handler[]) {
    this.handlers.push(...handlers)
  }

  delHandler(...handlers: Handler[]) {
    handlers.forEach(handler => {
      const index = this.handlers.indexOf(handler)
      if (index != -1) {
        this.handlers.splice(index, 1)
      }
    })
  }

  async execute(fn: (...args: any[]) => Promise<any>, ...args: any[]): Promise<any> {
    const context = new DefaultContext(args)

    let result = await Proxier.runHandles(this.handlers, context, 'getPrevHandle')
    if (result !== undefined) {
      return result
    }

    try {
      result = await fn(...args)

      context.setResult(result)
      return (await Proxier.runHandles(this.handlers, context, 'getPostHandle')) || result
    }
    catch(error) {
      context.setError(error)
      await Proxier.runHandles(this.handlers, context, 'getErrorHandle')
      
      throw error
    }
  }

}
